package com.woniu.zsd.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.woniu.zsd.common.util.MD5Util;
import com.woniu.zsd.common.util.RedisKey;
import com.woniu.zsd.common.util.StaticData;
import com.woniu.zsd.user.dto.UserDTO;
import com.woniu.zsd.user.entity.Account;
import com.woniu.zsd.user.entity.LoginLog;
import com.woniu.zsd.user.mapper.AccountMapper;
import com.woniu.zsd.user.mapper.LoginLogMapper;
import com.woniu.zsd.user.mapper.RoleMapper;
import com.woniu.zsd.user.param.ChatParam;
import com.woniu.zsd.user.param.LoginParam;
import com.woniu.zsd.user.param.SignUpParam;
import com.woniu.zsd.user.service.MqttGateway;
import com.woniu.zsd.user.service.UserService;
import com.woniu.zsd.user.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.zsd.user.mapper.UserMapper;
import net.sourceforge.tess4j.Tesseract;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.security.auth.login.AccountException;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private MqttGateway mqttGateway;
    @Resource
    private UserMapper userMapper;
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private LoginLogMapper loginLogMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Value(value = "${tess4j.datapath}")
    private String datapath;



    @Override
    public void chat(ChatParam param) {
        //redis存储单一用户的聊天记录
        param.setTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
        redisTemplate.opsForZSet().add(RedisKey.chatHistory(param.getRecyclingOrderNum()),param,System.currentTimeMillis());
        // 假设客服与用户的聊天主题为 "chat/user"
        mqttGateway.sendToMqtt("chat/"+param.getRecyclingOrderNum(), JSONUtil.toJsonStr(param));
    }

    @Override
    public void addUserPoint(Integer userId, Integer point) {
        User user = userMapper.selectById(userId);
        if (ObjectUtil.isEmpty(user)) throw new RuntimeException("用户不存在");
        user.setPoint(user.getPoint()+point);
        userMapper.updateById(user);
    }
    @Override
    public void sendSignUpCode(String phone) throws Exception {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        Account account = accountMapper.selectOne(queryWrapper);
        if (account != null) throw new RuntimeException("手机号已存在");
        if (stringRedisTemplate.hasKey(RedisKey.signUpCodeSendOneMinLimitKey(phone))) throw new RuntimeException("验证码发送过于频繁");
        //用户一小时内总验证码条数不能超过5条
        if(stringRedisTemplate.hasKey(RedisKey.sendCodeCountKey(phone))){
            int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(RedisKey.sendCodeCountKey(phone)));
            System.out.println("用户一小时内已发送验证码条数：" + count);
            if (count >= 5) throw new RuntimeException("一小时内发送验证码次数达到上限");
        }
        CorrelationData messageId = new CorrelationData(UUID.randomUUID().toString());
        HashMap<Object, Object> map = new HashMap<>();
        map.put("exchange","send.signup.code.ex");
        map.put("routingKey","send.signup.code");
        map.put("message",phone);
        String redisKey = RedisKey.rabbitmqMessageIdKey(messageId.getId());
        stringRedisTemplate.opsForHash().putAll(redisKey,map);
        rabbitTemplate.convertAndSend("send.signup.code.ex","send.signup.code", phone,messageId);
    }

    @Override
    public Integer getUserPoint(Integer userId) {
        User user = userMapper.selectById(userId);
        if (ObjectUtil.isEmpty(user)) throw new RuntimeException("用户不存在");
        return user.getPoint();
    }

    @Override
    public String recognizeIdCard(MultipartFile idCard) throws Exception{
        Tesseract tesseract = new Tesseract();
        tesseract.setDatapath(datapath);
        tesseract.setLanguage("chi_sim");
        BufferedImage image = ImageIO.read(idCard.getInputStream());
        return tesseract.doOCR(image);
    }

    @Override
    @Transactional
    public void signUp(SignUpParam param) throws Exception {
        RLock phoneNumberLock = redissonClient.getFairLock(RedisKey.lockPhone(param.getPhone()));
        RLock idLock = redissonClient.getFairLock(RedisKey.lockIdCardNumber(param.getIdCardNum()));
        RLock multiLock = redissonClient.getMultiLock(phoneNumberLock, idLock);
        try {
            multiLock.lock();
            QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", param.getPhone());
            if (accountMapper.selectOne(queryWrapper) != null) throw new RuntimeException("手机号已存在");
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("id_card_num", param.getIdCardNum());
            if (userMapper.selectOne(userQueryWrapper) != null) throw new RuntimeException("身份证号已存在");
            // 验证码是否过期
            if (!stringRedisTemplate.hasKey(RedisKey.signUpCodeKey(param.getPhone()))) throw new RuntimeException("验证码已过期");
            // 验证码是否正确
            if (!Objects.equals(stringRedisTemplate.opsForValue().get(RedisKey.signUpCodeKey(param.getPhone())), param.getSignUpCode())) throw new RuntimeException("验证码错误");
            Account account = new Account();
            account.setPhone(param.getPhone());
            account.setPassword(MD5Util.md5(param.getPassword(), param.getPhone()));
            account.setRoleId(StaticData.ROLE_USER);
            account.setStatus(StaticData.ACCOUNT_STATUS_ENABLED);
            account.setRegistrationTime(LocalDateTime.now());
            accountMapper.insert(account);
            User user = new User();
            user.setAccountId(account.getAccountId());
            user.setIdCardNum(param.getIdCardNum());
            user.setPoint(0);
            userMapper.insert(user);
        } finally {
            multiLock.unlock();
        }
    }

    @Override
    public UserDTO login(LoginParam param,HttpServletRequest request) throws Exception {
        Account account = accountMapper.selectOne(new QueryWrapper<Account>().eq("phone", param.getPhone()));
        if (account == null) throw new RuntimeException("用户不存在");
        if (Objects.equals(account.getStatus(), StaticData.ACCOUNT_STATUS_DISABLED)) throw new RuntimeException("用户已被禁用");
        if (!Objects.equals(account.getPassword(), MD5Util.md5(param.getPassword(), account.getPhone()))) throw new RuntimeException("密码错误");
        UserDTO userDTO = BeanUtil.toBean(account, UserDTO.class);
        userDTO.setRole(roleMapper.selectById(account.getRoleId()));
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("account_id", account.getAccountId()));
        if (ObjectUtil.isNotEmpty(user)) {
            BeanUtil.copyProperties(user, userDTO);
        }
        // 记录登录日志
        LoginLog loginLog = new LoginLog()
                .setAccountId(account.getAccountId())
                .setLastLogin(LocalDateTime.now())
                .setLoginIp(getClientIP(request))  // 需要实现IP获取方法
                .setLoginAddress(""); // 可根据IP解析地理信息
        loginLogMapper.insert(loginLog);
        return userDTO;
    }


    // 获取客户端IP方法
    private String getClientIP(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        System.out.println("客户端IP地址：" + ip);
        return ip;
    }
    @Override
    public Set selectChatHistory(Integer userId, String recyclingOrderNum) {
        if (redisTemplate.hasKey(RedisKey.chatHistory(recyclingOrderNum))){
            Set set = redisTemplate.opsForZSet().range(RedisKey.chatHistory(recyclingOrderNum), 0, -1);
            //向前端返回该排序集合

            set.forEach(System.out::println);
            return set;
        }
        throw new RuntimeException("没有聊天记录");
    }


}